home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / LIB / GLE / VIEW.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  9.1 KB  |  309 lines

  1.  
  2. /*
  3.  * MODULE Name: view.c
  4.  *
  5.  * FUNCTION:
  6.  * This module provides two different routines that compute and return
  7.  * viewing matrices.  Both routines take a direction and an up vector, 
  8.  * and return a matrix that transforms the direction to the z-axis, and
  9.  * the up-vector to the y-axis.
  10.  * 
  11.  * HISTORY:
  12.  * written by Linas Vepstas August 1991
  13.  * Added double precision interface, March 1993, Linas
  14.  */
  15.  
  16. #include <math.h>
  17. #include "rot.h"
  18. #include "gutil.h"
  19. #include "vvector.h"
  20.  
  21. /* ============================================================ */
  22. /*
  23.  * The uviewdirection subroutine computes and returns a 4x4 rotation
  24.  * matrix that puts the negative z axis along the direction v21 and 
  25.  * puts the y axis along the up vector.
  26.  *
  27.  * Note that this code is fairly tolerant of "weird" paramters.
  28.  * It normalizes when necessary, it does nothing when vectors are of
  29.  * zero length, or are co-linear.  This code shouldn't croak, no matter
  30.  * what the user sends in as arguments.
  31.  */
  32. #ifdef __GUTIL_DOUBLE
  33. void uview_direction_d (double m[4][4],        /* returned */
  34.                         double v21[3],        /* input */
  35.                         double up[3])        /* input */
  36. #else
  37. void uview_direction_f (float m[4][4],        /* returned */
  38.                         float v21[3],        /* input */
  39.                         float up[3])        /* input */
  40. #endif
  41. {
  42.    double amat[4][4];
  43.    double bmat[4][4];
  44.    double cmat[4][4];
  45.    double v_hat_21[3];
  46.    double v_xy[3];
  47.    double sine, cosine;
  48.    double len;
  49.    double up_proj[3];
  50.    double tmp[3];
  51.  
  52.    /* find the unit vector that points in the v21 direction */
  53.    VEC_COPY (v_hat_21, v21);    
  54.    VEC_LENGTH (len, v_hat_21);
  55.    if (len != 0.0) {
  56.       len = 1.0 / len;
  57.       VEC_SCALE (v_hat_21, len, v_hat_21);
  58.  
  59.       /* rotate z in the xz-plane until same latitude */
  60.       sine = sqrt ( 1.0 - v_hat_21[2] * v_hat_21[2]);
  61.       ROTY_CS (amat, (-v_hat_21[2]), (-sine));
  62.  
  63.    } else {
  64.  
  65.       /* error condition: zero length vecotr passed in -- do nothing */
  66.       IDENTIFY_MATRIX_4X4 (amat);
  67.    }
  68.  
  69.  
  70.    /* project v21 onto the xy plane */
  71.    v_xy[0] = v21[0];
  72.    v_xy[1] = v21[1];
  73.    v_xy[2] = 0.0;
  74.    VEC_LENGTH (len, v_xy);
  75.  
  76.    /* rotate in the x-y plane until v21 lies on z axis ---
  77.     * but of course, if its already there, do nothing */
  78.    if (len != 0.0) { 
  79.  
  80.       /* want xy projection to be unit vector, so that sines/cosines pop out */
  81.       len = 1.0 / len;
  82.       VEC_SCALE (v_xy, len, v_xy);
  83.  
  84.       /* rotate the projection of v21 in the xy-plane over to the x axis */
  85.       ROTZ_CS (bmat, v_xy[0], v_xy[1]);
  86.  
  87.       /* concatenate these together */
  88.       MATRIX_PRODUCT_4X4 (cmat, amat, bmat);
  89.  
  90.    } else {
  91.  
  92.       /* no-op -- vector is already in correct position */
  93.       COPY_MATRIX_4X4 (cmat, amat);
  94.    }
  95.  
  96.    /* up vector really should be perpendicular to the x-form direction --
  97.     * Use up a couple of cycles, and make sure it is, 
  98.     * just in case the user blew it.
  99.     */
  100.    VEC_PERP (up_proj, up, v_hat_21); 
  101.    VEC_LENGTH (len, up_proj);
  102.    if (len != 0.0) {
  103.  
  104.       /* normalize the vector */
  105.       len = 1.0/len;
  106.       VEC_SCALE (up_proj, len, up_proj);
  107.    
  108.       /* compare the up-vector to the  y-axis to get the cosine of the angle */
  109.       tmp [0] = cmat [1][0];
  110.       tmp [1] = cmat [1][1];
  111.       tmp [2] = cmat [1][2];
  112.       VEC_DOT_PRODUCT (cosine, tmp, up_proj);
  113.    
  114.       /* compare the up-vector to the x-axis to get the sine of the angle */
  115.       tmp [0] = cmat [0][0];
  116.       tmp [1] = cmat [0][1];
  117.       tmp [2] = cmat [0][2];
  118.       VEC_DOT_PRODUCT (sine, tmp, up_proj);
  119.    
  120.       /* rotate to align the up vector with the y-axis */
  121.       ROTZ_CS (amat, cosine, -sine);
  122.    
  123.       /* This xform, although computed last, acts first */
  124.       MATRIX_PRODUCT_4X4 (m, amat, cmat);
  125.  
  126.    } else {
  127.  
  128.       /* error condition: up vector is indeterminate (zero length) 
  129.        * -- do nothing */
  130.       COPY_MATRIX_4X4 (m, cmat);
  131.    }
  132. }
  133.  
  134. /* ============================================================ */
  135. #ifdef __STALE_CODE
  136. /*
  137.  * The uview_dire subroutine computes and returns a 4x4 rotation
  138.  * matrix that puts the negative z axis along the direction v21 and 
  139.  * puts the y axis along the up vector.
  140.  * 
  141.  * It computes exactly the same matrix as the code above
  142.  * (uview_direction), but with an entirely different (and slower)
  143.  * algorithm.
  144.  *
  145.  * Note that the code below is slightly less robust than that above --
  146.  * it may croak if the supplied vectors are of zero length, or are
  147.  * parallel to each other ... 
  148.  */
  149. void uview_dire (float m[4][4],        /* returned */
  150.                  float v21[3],        /* input */
  151.                  float up[3])        /* input */
  152. {
  153.    double theta;
  154.    float v_hat_21 [3];
  155.    float z_hat [3];
  156.    float v_cross_z [3];
  157.    float u[3];
  158.    float y_hat [3];
  159.    float u_cross_y [3];
  160.    double cosine;
  161.    float zmat [4][4];
  162.    float upmat[4][4];
  163.    float dot;
  164.  
  165.    /* perform rotation to z-axis only if not already 
  166.     * pointing down z */
  167.    if ((v21[0] != 0.0 ) || (v21[1] != 0.0)) {
  168.  
  169.       /* find the unit vector that points in the v21 direction */
  170.       VEC_COPY (v_hat_21, v21);    
  171.       VEC_NORMALIZE (v_hat_21);
  172.    
  173.       /* cosine theta equals v_hat dot z_hat */
  174.       cosine = - v_hat_21 [2];
  175.       theta = - acos (cosine);
  176.    
  177.       /* Take cros product with z -- we need this, because we will rotate
  178.        * about this axis */
  179.       z_hat[0] = 0.0;
  180.       z_hat[1] = 0.0;
  181.       z_hat[2] = -1.0;
  182.    
  183.       VEC_CROSS_PRODUCT (v_cross_z, v_hat_21, z_hat);
  184.       VEC_NORMALIZE (v_cross_z);
  185.    
  186.       /* compute rotation matrix that takes -z axis to the v21 axis */
  187.       urot_axis (zmat, (float) theta, v_cross_z);
  188.  
  189.    } else {
  190.  
  191.       IDENTIFY_MATRIX_4X4 (zmat);
  192.       if (v21[2] > 0.0) {
  193.          /* if its pointing down the positive z-axis, flip it, so that
  194.           * we point down negative z-axis.  We flip x so that the partiy
  195.           * isn't destroyed (looks like a rotation)
  196.           */
  197.          zmat[0][0] = -1.0;
  198.          zmat[2][2] = -1.0;
  199.       }
  200.    }
  201.    
  202.    /* --------------------- */
  203.    /* OK, now compute the part that takes the y-axis to the up vector */
  204.  
  205.    VEC_COPY (u, up);
  206.    /* the rotation blows up, if the up vector is not perpendicular to
  207.     * the v21 vector.  Let us make sure that this is so. */
  208.    VEC_PERP (u, u, v_hat_21);
  209.  
  210.    /* need to run the y axis through above x-form, to see where it went */
  211.    y_hat[0] = zmat [1][0];
  212.    y_hat[1] = zmat [1][1];
  213.    y_hat[2] = zmat [1][2];
  214.    
  215.    /* perform rotation to up-axis only if not already 
  216.     * pointing along y axis */
  217.    VEC_DOT_PRODUCT (dot, y_hat, u);
  218.    if ((-1.0 < dot) && (dot < 1.0))  {
  219.  
  220.       /* make sure that up really is a unit vector */
  221.       VEC_NORMALIZE (u);
  222.       /* cosine phi equals y_hat dot up_vec */
  223.       VEC_DOT_PRODUCT (cosine, u, y_hat);
  224.       theta = - acos (cosine);
  225.    
  226.       /* Take cross product with y */
  227.       VEC_CROSS_PRODUCT (u_cross_y, u, y_hat);
  228.       VEC_NORMALIZE (u_cross_y);
  229.    
  230.       /* As a matter of fact, u_cross_y points either in the v21 direction,
  231.        * or in the minus v21 direction.  In either case, we needed to compute 
  232.        * it, because the the arccosine function returns values only for 
  233.        * 0 to 180 degree, not 0 to 360, which is what we need.  The 
  234.        * cross-product helps us make up for this.
  235.        */
  236.       /* rotate about the NEW z axis (i.e. v21) by the cosine */
  237.       urot_axis (upmat, (float) theta, u_cross_y);
  238.  
  239.    } else {
  240.  
  241.       IDENTIFY_MATRIX_4X4 (upmat);
  242.       if (dot == -1.0) {
  243.          /* if its pointing along the negative y-axis, flip it, so that
  244.           * we point along the positive y-axis.  We flip x so that the partiy
  245.           * isn't destroyed (looks like a rotation)
  246.           */
  247.          upmat[0][0] = -1.0;
  248.          upmat[1][1] = -1.0;
  249.       }
  250.    }
  251.    
  252.    MATRIX_PRODUCT_4X4 (m, zmat, upmat);
  253.  
  254. }
  255. #endif /* __STALE_CODE */
  256.  
  257. /* ============================================================ */
  258. /*
  259.  * The uviewpoint subroutine computes and returns a 4x4 matrix that 
  260.  * translates the origen to the point v1, puts the negative z axis
  261.  * along the direction v21==v2-v1, and puts the y axis along the up
  262.  * vector.
  263.  */
  264. #ifdef __GUTIL_DOUBLE
  265. void uviewpoint_d (double m[4][4],        /* returned */
  266.                    double v1[3],        /* input */
  267.                    double v2[3],        /* input */
  268.                    double up[3])        /* input */
  269. #else 
  270. void uviewpoint_f (float m[4][4],        /* returned */
  271.                    float v1[3],        /* input */
  272.                    float v2[3],        /* input */
  273.                    float up[3])        /* input */
  274. #endif
  275. {
  276. #ifdef __GUTIL_DOUBLE
  277.    double v_hat_21 [3];
  278.    double trans_mat[4][4];
  279.    double rot_mat[4][4];
  280. #else
  281.    float v_hat_21 [3];
  282.    float trans_mat[4][4];
  283.    float rot_mat[4][4];
  284. #endif
  285.  
  286.    /* find the vector that points in the v21 direction */
  287.    VEC_DIFF (v_hat_21, v2, v1);
  288.  
  289.    /* compute rotation matrix that takes -z axis to the v21 axis,
  290.     * and y to the up dierction */
  291. #ifdef __GUTIL_DOUBLE
  292.    uview_direction_d (rot_mat, v_hat_21, up);
  293. #else
  294.    uview_direction_f (rot_mat, v_hat_21, up);
  295. #endif
  296.  
  297.    /* build matrix that translates the origin to v1 */
  298.    IDENTIFY_MATRIX_4X4 (trans_mat);
  299.    trans_mat[3][0] = v1[0];
  300.    trans_mat[3][1] = v1[1];
  301.    trans_mat[3][2] = v1[2];
  302.  
  303.    /* concatenate the matrices together */
  304.    MATRIX_PRODUCT_4X4 (m, rot_mat, trans_mat);
  305.  
  306. }
  307.  
  308. /* ================== END OF FILE ============================ */
  309.